// XML utilities   
function loadObjectFromXmlNode(obj, node, bTrimSpaces) {
    if (arguments.length < 3) {
        bTrimSpaces = true;
    }
    // load attributes
    for (var i = 0; i < node.attributes.length; i++) {
        var attr = node.attributes[i];
        obj[attr.nodeName] = attr.nodeValue;
    }
    // load child nodes
    var children = node.childNodes;
    for (var i = 0; i < children.length; i++) {
        var child = children[i];
        var value = getNodeValue(child);
        if (bTrimSpaces) {
            value = stripWhitespace(value);
        }
//        if (!!value)
        if (value != null) {
            obj[child.nodeName.toLowerCase()] = value;
        }
        else if (child.tagName) {
            var childObj = new Array();
            loadObjectFromXmlNode(childObj, child);
            var nodeName = child.nodeName.toLowerCase();
            if (obj[nodeName]) {
                //looks like this is a collection (object with the same key already exists)
                //this dummy value indicates that there are more items with this name
                var __COLLECTION = "__collection__";
                if (obj[nodeName] != __COLLECTION) {
                    var prevObj = obj[nodeName];
                    obj[nodeName] = __COLLECTION;
                    obj.push(prevObj);
                }
                obj.push(childObj);
            }
            else {
                obj[nodeName] = childObj;
            }
        }
    }

    // remove __COLLECTION dummies
    for (var i = 0; i < obj.length; i++)
    {
        if (obj[i] == __COLLECTION)
            obj.pop(i);
    }
}

function createObjectFromXml(node, bTrimSpaces)
{
    if (arguments.length < 2) {
        bTrimSpaces = true;
    }
    var obj = new Object();
    loadObjectFromXmlNode(obj, node, bTrimSpaces);
    return obj;
}

// Get value of simple node like <Node>Node value</Node> or <Node/>
function getNodeValue(node)
{
    var children = node.childNodes;
    var value = null;
    if (children.length === 1 && node.firstChild.nodeType == Node.TEXT_NODE) {
        if (node.firstChild.nodeValue) {
            value = node.firstChild.nodeValue;
        }
        else {
            value = "";
        }
    }
    else if (children.length === 0) {
        value = "";
    }
    return value;
}

function stripWhitespace(str)
{
    var s = str;
    if (s)
    {
//        s = s.replace(/[\r\n]/g, "");
//        s = s.replace(/>(\s+)</g, "><");
//        s = s.replace(/^\s*(\w*)\s*$/g, "$1");
        s = s.replace(/^\s+/, "");
        s = s.replace(/\s+$/, "");
    }
    return s;
}

function xmlGetFirstChild(node)
{
    var children = node.childNodes;
    for (var i = 0; i < children.length; i++)
    {
        var child = children[i];
        if (child.tagName)
            return child;
    }
    return null;
}

function xmlGetNextSibling(node)
{
    var sibling = node.nextSibling;
    while(sibling && !sibling.tagName)
        sibling = sibling.nextSibling;
    return sibling;
}

